#include "../libc/function.h"
#include "../libc/string.h"
#include "../cpu/port.h"
#include "../driver/screen.h"
#include "../driver/keyboard.h"
#include "idt.h"
#include "timer.h"
#include "isr.h"

isr_t isr_handlers[IDT_ENTRY_NUM];
char *exception_messages[] = {
    "Division By Zero",
    "Debug",
    "Non Maskable Interrupt",
    "Breakpoint",
    "Into Detected Overflow",
    "Out of Bounds",
    "Invalid Opcode",
    "No Coprocessor",

    "Double Fault",
    "Coprocessor Segment Overrun",
    "Bad TSS",
    "Segment Not Present",
    "Stack Fault",
    "General Protection Fault",
    "Page Fault",
    "Unknown Interrupt",

    "Coprocessor Fault",
    "Alignment Check",
    "Machine Check",
    "Reserved",
    "Reserved",
    "Reserved",
    "Reserved",
    "Reserved",

    "Reserved",
    "Reserved",
    "Reserved",
    "Reserved",
    "Reserved",
    "Reserved",
    "Reserved",
    "Reserved"
};

void isr_install() {
    set_idt_gate(0,  (uint32_t) isr0);
    set_idt_gate(1,  (uint32_t) isr1);
    set_idt_gate(2,  (uint32_t) isr2);
    set_idt_gate(3,  (uint32_t) isr3);
    set_idt_gate(4,  (uint32_t) isr4);
    set_idt_gate(5,  (uint32_t) isr5);
    set_idt_gate(6,  (uint32_t) isr6);
    set_idt_gate(7,  (uint32_t) isr7);
    set_idt_gate(8,  (uint32_t) isr8);
    set_idt_gate(9,  (uint32_t) isr9);
    set_idt_gate(10,  (uint32_t) isr10);
    set_idt_gate(11,  (uint32_t) isr11);
    set_idt_gate(12,  (uint32_t) isr12);
    set_idt_gate(13,  (uint32_t) isr13);
    set_idt_gate(14,  (uint32_t) isr14);
    set_idt_gate(15,  (uint32_t) isr15);
    set_idt_gate(16,  (uint32_t) isr16);
    set_idt_gate(17,  (uint32_t) isr17);
    set_idt_gate(18,  (uint32_t) isr18);
    set_idt_gate(19,  (uint32_t) isr19);
    set_idt_gate(20,  (uint32_t) isr20);
    set_idt_gate(21,  (uint32_t) isr21);
    set_idt_gate(22,  (uint32_t) isr22);
    set_idt_gate(23,  (uint32_t) isr23);
    set_idt_gate(24,  (uint32_t) isr24);
    set_idt_gate(25,  (uint32_t) isr25);
    set_idt_gate(26,  (uint32_t) isr26);
    set_idt_gate(27,  (uint32_t) isr27);
    set_idt_gate(28,  (uint32_t) isr28);
    set_idt_gate(29,  (uint32_t) isr29);
    set_idt_gate(30,  (uint32_t) isr30);
    set_idt_gate(31,  (uint32_t) isr31);

    // 重新映射irq 0-15 到 32-47
    /* 1. 向主/从 PIC 端口 0x20/0xA0 发送 ICW1：初始化 + 级联模式 */
    port_byte_out(0x20, 0x11);   // 主 PIC：bit4=1 表示初始化，bit0=1 表示需要 ICW4
    port_byte_out(0xA0, 0x11);   // 从 PIC：同上

    /* 2. ICW2：设置中断向量起始号 */
    port_byte_out(0x21, 0x20);   // 主 PIC IRQ0-7  -> 向量 0x20-0x27
    port_byte_out(0xA1, 0x28);   // 从 PIC IRQ8-15 -> 向量 0x28-0x2F

    /* 3. ICW3：级联线路信息 */
    port_byte_out(0x21, 0x04);   // 主 PIC：IRQ2（bit2=1）接从片
    port_byte_out(0xA1, 0x02);   // 从 PIC：自己的级联输入接在主 PIC 的 IRQ2

    /* 4. ICW4：附加模式字 */
    port_byte_out(0x21, 0x01);   // 8086/88 模式
    port_byte_out(0xA1, 0x01);   // 同上

    /* 5. OCW1：屏蔽所有 IRQ（可选，后面再按需 unmask） */
    port_byte_out(0x21, 0x00);   // 主 PIC：0 = 全部不屏蔽
    port_byte_out(0xA1, 0x00);   // 从 PIC：0 = 全部不屏蔽

    set_idt_gate(32,  (uint32_t) irq0);
    set_idt_gate(33,  (uint32_t) irq1);
    set_idt_gate(34,  (uint32_t) irq2);
    set_idt_gate(35,  (uint32_t) irq3);
    set_idt_gate(36,  (uint32_t) irq4);
    set_idt_gate(37,  (uint32_t) irq5);
    set_idt_gate(38,  (uint32_t) irq6);
    set_idt_gate(39,  (uint32_t) irq7);
    set_idt_gate(40,  (uint32_t) irq8);
    set_idt_gate(41,  (uint32_t) irq9);
    set_idt_gate(42,  (uint32_t) irq10);
    set_idt_gate(43,  (uint32_t) irq11);
    set_idt_gate(44,  (uint32_t) irq12);
    set_idt_gate(45,  (uint32_t) irq13);
    set_idt_gate(46,  (uint32_t) irq14);
    set_idt_gate(47,  (uint32_t) irq15);

    set_idt();
}

void irq_install() {
    // 开启设备中断
    asm volatile("sti");
    // 设置定时器 50Hz
    init_keyboard();
    init_timer(50);
}

void isr_handler(isr_registers_t* reg) {
    kprint("received interrupt: ");
    char s[3];
    int2ascii(reg->int_no, s);
    kprint(s);
    kprint(" ");
    kprint(exception_messages[reg->int_no]);
    kprint("\n");
    UNUSED(reg);
}

uint32_t irq_handler(isr_registers_t *reg) {
    // 发送EOI以允许继续接受中断
    if(reg->int_no >= 40) port_byte_out(0xA0, 0x20);
    port_byte_out(0x20, 0x20);

    if(isr_handlers[reg->int_no] != 0) {
        isr_t handler = isr_handlers[reg->int_no];
        return handler(reg);
    }
    return (uint32_t)reg;
}

void isr_handler_register(int n, isr_t handler) {
    isr_handlers[n] = handler;
}